namespace("lesp.songmeanings");

/**
 * SongMeanings' manager. Searches for a song of given artist.
 */
lesp.songmeanings.Manager = lesp.abstract.Manager.extend({

  _searchUrlTemplate : "http://songmeanings.com/query/?q={0}&type=artists",
  _baseUrl           : "http://songmeanings.com",


  _onLoad : function(response)
  {
    if(response.finalUrl.indexOf(this._baseUrl + "/artist") == 0)
    {
      // exact match redirect
      this._onArtistSongsLoad(response);
    }
    else if(response.finalUrl.indexOf("https://www.google") == 0)
    {
      // google search fallback
      var contents = jQuery(lesp.mangleHtml(response.responseText));
      var search   = "{0}/artist".format(this._baseUrl.replace("http://", ""));
      var links    = contents.find("cite").get().filter((function(element)
      {
        return jQuery(element).text().indexOf(search) == 0;
      }).bind(this));
      
      if(links.length)
      {
        GM_xmlhttpRequest({
          method  : "get",
          url     : "http://" + jQuery(links[0]).text(),
          onload  : this._onArtistSongsLoad.bind(this),
          onerror : this.notify.bind(this, "failed")
        });
      }
      else
      {
        this.notify("failed");
      }
    }
    else
    {
      var contents = jQuery(lesp.mangleHtml(response.responseText));
      var artist   = contents.find("#content-big tr.item td a:eq(0)");

      if(artist.length)
      {
        var url = artist.attr("href");
        if(url.indexOf(this._baseUrl) != 0)
        {
          url = this._baseUrl + url;
        }
        
        GM_xmlhttpRequest({
          method  : "get",
          url     : url,
          onload  : this._onArtistSongsLoad.bind(this),
          onerror : this.notify.bind(this, "failed")
        });
      }
      else
      {
        this.notify("failed");
      }
    }
  },

  _onArtistSongsLoad : function(response)
  {
    var contents = jQuery(lesp.mangleHtml(response.responseText));

    var track      = this._track.toLowerCase();
    var candidates = contents.find("#songslist td:not(.comments) a")
      .map(function()
      {
        var item     = jQuery(this);
        var distance = item.text().toLowerCase().distance(track);
        
        // jQuery filters nulls and concats returned arrays
        return distance < 8 ? {dist : distance, href : item.attr("href"), name : item.text()} : null;  
      })
      .get()
      .sort(function(a, b)
      {
        return a.dist - b.dist;
      });
    
    if(candidates.length)
    {
      this._songUrlQuery = candidates[0].href;

      var song = new lesp.songmeanings.Song(candidates[0]);
      song.attach("loaded",    this.notify.bind(this, "loaded", song));
      song.attach("notLoaded", this.notify.bind(this, "failed"));

      this.notify("found");
    }
    else
    {
      this.notify("failed");
    }
  }

});

/**
 * SongMeanings' song page. Retrives lyrics.
 */
lesp.songmeanings.Song = lesp.abstract.Song.extend({

  _baseUrl         : "http://songmeanings.com",
  _commentCache    : null,
  _commentDocument : null, 


  getLyrics : function()
  {
    if(!this._document)
    {
      throw new Error("Song document is not yet ready");
    }

    var result = this._document.find("div.lyric-box");
    result.find("div").remove(); // button container
    
    var text = result.text().replace(/�/g, "'"); 

    return text;
  },
  
  _onLoad : function(response)
  {
    this._document = jQuery(lesp.mangleHtml(response.responseText));
    
    GM_xmlhttpRequest({
      method  : "post",
      url     : this._pageUrl,
      data    : "command=loadComments",
      headers : {
        "X-Requested-With" : "XMLHttpRequest",
        "Content-Type"     : "application/x-www-form-urlencoded"
      },
      onload  : (function(response)
      {
        this._commentDocument = jQuery("<div>{0}</div>".format(response.responseText));
        this.notify("loaded");
      }).bind(this),
      onerror : this.notify.bind(this, "notLoaded")
    });
  },
  
  getCommentCount : function()
  {
    var match = /\d+/.exec(this._document.find("#header-comments-counter").text());
    
    return match ? Number(match[0]) : 0; 
  },
  
  getFirstComments : function()
  {
    if(!this._commentDocument)
    {
      throw new Error("Comment document is not yet ready");
    }
    
    if(this._commentCache)
    {
      return this._commentCache; 
    }
    
    return this._commentCache = this._commentDocument.find("li div.text").map(function()
    {
      var comment = jQuery(this);
      
      var user = comment.find(".sign a.author:eq(0)").text();
      var date = comment.find(".sign em.date:eq(0)").text();
      var text = comment.contents().map(function()
      {
        if(this.nodeName == "#text")
        {
          return jQuery.trim(this.wholeText);
        }
        else if(this.nodeName == "BR")
        {
          return "<br/>";
        }
      }).get().join("");
      
      return {
        user : user,
        date : date,
        text : text
      };
    }).get();
  }

});

/**
 * SongMeanings' song renderer. Creates ready DOM node for lyrics.
 */
lesp.songmeanings.Renderer = lesp.abstract.Renderer.extend({

  _title : "SongMeanings",


  _createLyrics : function()
  {
    return jQuery("<div/>")
      .append("<h4>Lyrics</h4>")
      .append(
        jQuery("<div style='padding-left: 25px;'/>").html(this._song.getLyrics()
          .replace(/^[\s]+/g, "<br/>")
          .replace(/[\s]+$/g, "<br/>")
          .replace(/\n/g, "<br/>")
        )
      )
      .html(); // doesn't include outer div
  },

  _createMenu : function()
  {
    var result = jQuery("<div style='text-align: right; padding: 5px 10px 10px 0; font-size: 11px;'/>");
    
    var commentsTotal  = this._song.getCommentCount();
    var commentPostfix = ""; 
    if(commentsTotal)
    {
      var commentsLoaded = this._song.getFirstComments().length;
      if(commentsTotal > commentsLoaded)
      {
        commentPostfix = " ({0}/{1})".format(commentsLoaded, commentsTotal);
      }
    
      result.append(
        "<a href='#songmeanings-commnets' class='info show-comments'>Show comments{0}</a>"
          .format(commentPostfix)
      );
      result.append("<span style='padding-left: 10px;'/>");
    }
    
    result.append(
      "<a href='{0}' class='info' target='_blank'>SongMeanings page</a>".format(this._song.getPageUrl())
    );

    result.find("a.show-comments").click(function()
    {
      var anchor = jQuery(this);

      anchor.parent()
        .next().toggle()
        .next().toggle();

      anchor.text((anchor.data("shown") ? "Show comments" : "Hide comments") + commentPostfix);
      anchor.data("shown", !anchor.data("shown"));
    });

    return result;
  },

  _createComments : function()
  {
    var comments = this._song.getFirstComments().map(function(comment)
    {
      var template = "<li><div>{0}</div><span style='color: #696969'>- {1} {2}</span></li>"; 
      return template.format(comment.text, comment.user, comment.date);
    }).join("");
    
    return comments 
      ? [
        "<h4 id='songmeanings-commnets' style='display:none;'>Comments</h4>",
        "<ul class='journalsSmall' style='display:none; overflow:auto; height:450px; font-size:12px;'>",
        comments,
        "</ul>"
      ].join("")
      : "";
  },
  
  render : function()
  {
    return jQuery("<div/>")
      .append(this._createMatchNotice())
      .append(this._createLyrics())
      .append(this._createMenu())
      .append(this._createComments());
  }

});


